extern "C"
{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
}
#include "ThreadBase.h"

//构造函数，通过参数列表方式给线程号初始化为0
ThreadBase::ThreadBase():tid(0)
{
    memset(&m_input_context, 0, sizeof(m_input_context));
    memset(&m_output_context, 0, sizeof(m_output_context));
}

//虚析构函数
ThreadBase::~ThreadBase()
{
    printf("~ThreadBase\n");
}


/****************************************************************
@功能：启动线程
@参数：无
@返回值: 成功：0，失败：-1
******************************************************************/
int ThreadBase::start()
{
    int ret = 0;

    size_t nsize = 1024*200; //200k
    ret = pthread_attr_init(&t_attr); //初始化线程属性
    if(ret != 0)
    {
        perror("pthread_attr_init");
        return -1;
    }

    //设置线程的堆栈大小
    ret = pthread_attr_setstacksize(&t_attr, nsize);
    if(ret != 0)
    {
        perror("pthread_attr_getstacksize");
         return -1;
    }

    //创建线程
    return pthread_create(&tid, &t_attr, work, this);
}

/****************************************************************
@功能：线程的运行函数，此处为空，由派生类实现
@参数：无
@返回值: 无
******************************************************************/
void ThreadBase::routine()
{

}

/****************************************************************
@功能：获取当前线程的线程号
@参数：无
@返回值: 线程号
******************************************************************/
pthread_t ThreadBase::self()
{
    if(!tid)
    {
        tid = pthread_self(); //获取线程号
    }

    return tid;
}

/****************************************************************
@功能：比较线程号是否相等
@参数：待比较的线程号
@返回值: 相等：0，不相等：-1
******************************************************************/
int ThreadBase::equal(pthread_t t)
{
    int ret = 0;
    ret = pthread_equal(tid, t);
    return (ret)?0:-1;
}

/****************************************************************
@功能：分离线程，待线程结束时让系统自动回收其资源
@参数：无
@返回值: 成功：0，失败：-1
******************************************************************/
int ThreadBase::detach()
{
    return pthread_detach(tid);
}

/****************************************************************
@功能：连接线程，等待指定的线程结束，并回收其资源
@参数：无
@返回值: 成功：0，失败：-1
******************************************************************/
int ThreadBase::join(pthread_t t)
{
    return pthread_join(t, NULL);
}

/****************************************************************
@功能：线程退出
@参数：无
@返回值: 成功：0，失败：-1
******************************************************************/
int ThreadBase::exit()
{
    int ret = 0;
    pthread_exit(NULL);
    return ret;
}

/****************************************************************
@功能：取消线程
@参数：线程号
@返回值: 成功：0，失败：-1
******************************************************************/
int ThreadBase::cancel(pthread_t t)
{
    return  pthread_cancel(t);
}

/****************************************************************
@功能：销毁线程
@参数：线程号
@返回值: 成功：0，失败：-1
******************************************************************/
int ThreadBase::destroy()
{
    return cancel(tid);
}

/****************************************************************
@功能：线程清理函数
@参数：线程句柄
@返回值: 无
******************************************************************/
void ThreadBase::cleaner(void *pHandle)
{
    ThreadBase *p = (ThreadBase *)pHandle;
    delete p;
    p = NULL;
    printf("after clean\n");
}

/****************************************************************
@功能：线程回调函数
@参数：线程句柄
@返回值: 无
******************************************************************/
void *ThreadBase::work(void *pHandle)
{
    ThreadBase* pThread = (ThreadBase *)pHandle;

    //注册线程处理函数
    pthread_cleanup_push(cleaner, pHandle);

    pThread->routine(); //线程运行函数

    //线程资源释放，参数为非0
    pthread_cleanup_pop(1);

    return NULL;
}

void ThreadBase::init_output_context(unsigned long data_size)
{
    if(m_output_context.buffer)
        free(m_output_context.buffer);
    m_output_context.buffer = new unsigned char(data_size);
    m_output_context.data_size = data_size;
    m_output_context.mutex = PTHREAD_MUTEX_INITIALIZER;
    /* @prototype: int sem_init(sem_t *sem, int pshared, unsigned int value); */
    /* pshared: if pshared == 0, the semaphore is shared among threads of a process
     * otherwise the semaphore is shared between processes.   */
    sem_init(&m_output_context.sem, 0, 0);
}

ThreadDataExcangeContext* ThreadBase::get_output_context()
{
    return &m_output_context;
}

void ThreadBase::init_input_context(ThreadDataExcangeContext* context)
{
    m_input_context = context;
}




void ThreadBase::free_output_context()
{
    if(m_output_context.buffer!=nullptr)
    {
        lock_output_buffer();
        delete m_output_context.buffer;
        m_output_context.buffer = nullptr;
        unlock_output_buffer();
    }
    m_output_context.data_size = 0;
    sem_destroy(&m_output_context.sem);
    lock_output_buffer();
}


void ThreadBase::lock_input_buffer()
{
    if(m_input_context)
        pthread_mutex_lock(&m_input_context->mutex);
}

void ThreadBase::unlock_input_buffer()
{
    if(m_input_context)
        pthread_mutex_unlock(&m_input_context->mutex);
}

void ThreadBase::lock_output_buffer()
{
    pthread_mutex_lock(&m_output_context.mutex);
}

void ThreadBase::unlock_output_buffer()
{
    pthread_mutex_unlock(&m_output_context.mutex);
}



void ThreadBase::wait_input_new_message()
{
    if(m_input_context)
    {
        sem_wait(&m_input_context->sem); // P
    }
}

unsigned char ThreadBase::try_input_new_message()
{
    if(m_input_context)
    {
        int ret = sem_trywait(&m_input_context->sem); // P
        if(ret==0)
        {
            return 1; // P success, new message
        }
        if(ret==-1)
        {
            return 0; // P failure, no new message
        }
    }
    return 0;
}


void ThreadBase::get_input_buffer(unsigned char* dst)
{
    memcpy(dst, m_input_context->buffer, m_input_context->data_size);
}

unsigned long ThreadBase::get_input_size()
{
    if(m_input_context)
        return m_input_context->data_size;
    else
        return 0;
}

unsigned long ThreadBase::get_output_size()
{
    return m_output_context.data_size;
}

void ThreadBase::set_output_new_message(unsigned char flag)
{
    if(flag)
    {
        sem_trywait(&m_output_context.sem); // P, if the previous new message is not read, drop it.
        sem_post(&m_output_context.sem); // V
    }
    else
    {
        sem_trywait(&m_output_context.sem); // P, if the previous new message is not read, drop it.
    }
}

void ThreadBase::write_output_buffer(unsigned char* buffer)
{
    memcpy(m_output_context.buffer, buffer, m_output_context.data_size);
}
